home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-09-28 | 21.0 KB | 670 lines | [TEXT/CWIE] |
- /*
- File: ARPerations.c
-
- Contains: Standard high-level ARP operations.
-
- Written by: Quinn "The Eskimo!"
-
- Copyright: Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/21/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
- fixed output problem by changing '\r' to '\n'
- OSStatus ARPGetCacheReport(Handle cacheReport)
-
-
- */
- // Lots of standard OT constructs.
-
- #include <OpenTransport.h>
- #include <OpenTptClient.h>
-
- ///////////////////////////////////////////////////////////////////
- // Pick up the names of the standard OT modules.
-
- #include <modnames.h>
-
- ///////////////////////////////////////////////////////////////////
- // Pick up types and constants for I_STR ioctls.
-
- #include <stropts.h>
-
- ///////////////////////////////////////////////////////////////////
- // Pick up handle operations for ARPGetCacheReport.
-
- #include <Memory.h>
-
- ///////////////////////////////////////////////////////////////////
- // Standard C string operations.
-
- #include <string.h>
-
- ///////////////////////////////////////////////////////////////////
- // Constants and types for ARP module messages.
-
- #include "OTARPModule.h"
-
- ///////////////////////////////////////////////////////////////////
- // Our own prototypes.
-
- #include "ARPerations.h"
-
- ///////////////////////////////////////////////////////////////////
-
- // The following equates are actually exported by <miioccom.h>, but
- // they are commented out for some reason )-: So instead of including
- // <miioccom.h> we just define them again here.
-
- #define MIOC_ND 'c' /* ioctl's for Mentat's nd device */
-
- // The following equates define the two "Name Dispatch" ioctls
- // for setting and getting OT internal parameters.
-
- #define ND_GET MIOC_CMD(MIOC_ND, 0) /* Get a value */
- #define ND_SET MIOC_CMD(MIOC_ND, 1) /* Set a value */
-
- // The name of the Name Dispatch variable you have to get in
- // order to get a dump of the ARP cache.
-
- #define ARP_ND_CACHE_REPORT "arp_cache_report"
-
- enum {
- kARP_ND_CACHE_REPORT_Length = 17 // strlen(ARP_ND_CACHE_REPORT) + 1
- };
-
- OSStatus ARPGetCacheReport(Handle cacheReport)
- // See comment in header file.
- {
- OSStatus err;
- StreamRef arpStream;
- struct strioctl nddIOCommand;
- SInt32 i;
- char ndCommandBuffer[kARP_ND_CACHE_REPORT_Length];
- UInt32 realDataSize;
- SInt8 cacheReportHandleState;
-
- // First open up a raw STREAMS connection to the ARP module.
-
- arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
-
- if (err == noErr) {
-
- // Switch the stream in sync/blocking mode. To make the
- // code easier, we're going to do this synchronously.
-
- (void) OTStreamSetBlocking(arpStream);
- (void) OTStreamSetSynchronous(arpStream);
-
- // Copy the name of the ND variable we're trying
- // to get into our buffer.
-
- OTStrCopy(ndCommandBuffer, ARP_ND_CACHE_REPORT);
-
- // The ND_GET ioctl returns a value and sets ic_len. A negative
- // value is an error and you can give up now (-: The rule for
- // positive values is a bit weirder. ic_len is always set
- // to the amount of data that is actually returned. If the
- // data available exceeds the available buffer space (as
- // defined by the ic_len on input), the ioctl returns
- // a positive number that is the amount of buffer space
- // needed. So we first call it with a minimal buffer
- // then give it the buffer space it requires. Obviously
- // there's a concurrency race here, which we conveniently
- // ignore in this sample by return kEAGAINErr.
-
- // First get the size of data buffer we need to allocate by
- // doing the ioctl with a small buffer and examining the result.
-
- nddIOCommand.ic_cmd = ND_GET;
- nddIOCommand.ic_timout = 0;
- nddIOCommand.ic_len = kARP_ND_CACHE_REPORT_Length; // Length of ND name including...
- nddIOCommand.ic_dp = ndCommandBuffer; // ...the zero terminator.
-
- err = OTStreamIoctl(arpStream, I_STR, &nddIOCommand);
-
- if (err >= noErr) {
-
- if (err > noErr) {
-
- // The first ioctl returned a positive number telling
- // us how big the data returned was. We turn around
- // around make the ioctl again, this time passing
- // in an appropriately sized buffer.
-
- realDataSize = err;
- SetHandleSize(cacheReport, realDataSize);
- err = MemError();
-
- if (err == noErr) {
- cacheReportHandleState = HGetState(cacheReport);
- HLock(cacheReport);
-
- OTStrCopy(*cacheReport, ARP_ND_CACHE_REPORT);
-
- nddIOCommand.ic_cmd = ND_GET;
- nddIOCommand.ic_timout = 0;
- nddIOCommand.ic_len = realDataSize;
- nddIOCommand.ic_dp = *cacheReport;
-
- err = OTStreamIoctl(arpStream, I_STR, &nddIOCommand);
-
- HSetState(cacheReport, cacheReportHandleState);
- }
- }
-
- if (err == noErr) {
-
- // Everything is cool, we have the ARP report. Now
- // all we have remaining is a trivial format
- // conversion. The format returned is straight
- // text with zero characters as the line terminator.
- // We mutate the line terminators into standard EOL '\n'
-
- for (i = 0; i < realDataSize; i++) {
- if ( (*cacheReport)[i] == '\0' ) {
- (*cacheReport)[i] = '\n';
- }
- }
-
- } else {
- // Whoah, ARP table changed size!
- err = kEAGAINErr;
- }
- }
- }
-
- // Clean up.
-
- if (arpStream != nil) {
- (void) OTStreamClose(arpStream);
- }
- return (err);
- }
-
- ///////////////////////////////////////////////////////////////////
-
- // The following routines are used to copy variable length data structures
- // in the ARP command block that we're assembling.
-
- static void CopyIntoCommandBuffer(char *buffer, UInt32 *currentOffset, void *data, UInt32 dataLength)
- // Copy dataLength bytes from data into an ARP command buffer.
- // buffer is a pointer to an ARP command block.
- // currentOffset comes in as the number of bytes that are currently being
- // used in the block, and is adjusted to represent the number of bytes we copied in.
- // data is the address of the bytes to copy in.
- // dataLength is the number of bytes to copy in.
- {
- OTMemcpy(&buffer[*currentOffset], data, dataLength);
- (*currentOffset) += dataLength;
- }
-
- static void CopyInterfaceIntoCommandBuffer(char *buffer, UInt32 *currentOffset, char *interfaceName)
- // Copy an interface name into an ARP command buffer.
- // buffer is a pointer to an ARP command block. This is assumed to point
- // to at least an arc_t, although the other ARP command structures all
- // begin with an arc_t, so it works for the other structures as well.
- // currentOffset comes in as the number of bytes that are currently being
- // used in the block, and is adjusted to represent the number of bytes we copied in.
- // interfaceName is the address of a C string.
- {
- arc_t *arpCommandPtr;
- UInt32 interfaceNameLength;
-
- interfaceNameLength = OTStrLength(interfaceName) + 1; // copy the string and the final null
- arpCommandPtr = (arc_t *) buffer;
- arpCommandPtr->arc_name_offset = *currentOffset;
- arpCommandPtr->arc_name_length = interfaceNameLength;
- CopyIntoCommandBuffer(buffer, currentOffset, interfaceName, interfaceNameLength);
- }
-
- static void CopyProtoIntoCommandBuffer(char *buffer, UInt32 *currentOffset,
- void *protoAddress, UInt32 protoSize)
- // Copy an protocol address into an ARP command buffer.
- // buffer is a pointer to an ARP command block. This is assumed to point
- // to at least an arc_t, although the other ARP command structures all
- // begin with an arc_t, so it works for the other structures as well.
- // currentOffset comes in as the number of bytes that are currently being
- // used in the block, and is adjusted to represent the number of bytes we copied in.
- // protoAddress is the address of the bytes of the protocol address to copy in.
- // protoSize is the number of bytes to copy in.
- {
- arc_t *arpCommandPtr;
-
- arpCommandPtr = (arc_t *) buffer;
- arpCommandPtr->arc_proto_addr_offset = *currentOffset;
- arpCommandPtr->arc_proto_addr_length = protoSize;
- CopyIntoCommandBuffer(buffer, currentOffset, protoAddress, protoSize);
- }
-
- ///////////////////////////////////////////////////////////////////
-
- OSStatus ARPAddEntry(char *interfaceName,
- UInt32 arpProto,
- UInt32 flags,
- void *protoAddress, UInt32 protoSize, void *protoMask,
- void *hardwareAddress, UInt32 hardwareSize)
- // See comment in header file.
- {
- OSStatus err;
- StreamRef arpStream;
- char arpCommandBuffer[256];
- area_t *arpAddCommandPtr;
- UInt32 currentOffset;
- struct strioctl arpIOControl;
-
- // First up, open a simple stream to the ARP as a driver.
-
- arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
-
- if (err == noErr) {
- (void) OTStreamSetBlocking(arpStream);
- (void) OTStreamSetSynchronous(arpStream);
-
- // Initialise the command buffer for this command.
-
- arpAddCommandPtr = (area_t *) &arpCommandBuffer[0];
- currentOffset = sizeof(area_t);
-
- arpAddCommandPtr->area_arc.arc_cmd = AR_ENTRY_ADD;
-
- CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
-
- arpAddCommandPtr->area_arc.arc_proto = arpProto;
-
- CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
-
- arpAddCommandPtr->area_arc.arc_flags = flags;
- arpAddCommandPtr->area_arc.arc_client_q = nil; // ignored by ARP for this command
-
- arpAddCommandPtr->area_proto_mask_offset = currentOffset;
- CopyIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoMask, protoSize);
-
- arpAddCommandPtr->area_hw_addr_offset = currentOffset;
- arpAddCommandPtr->area_hw_addr_length = hardwareSize;
- CopyIntoCommandBuffer(arpCommandBuffer, ¤tOffset, hardwareAddress, hardwareSize);
-
- // Initialise the I_STR ioctl structure.
-
- arpIOControl.ic_cmd = AR_ENTRY_ADD;
- arpIOControl.ic_timout = 0;
- arpIOControl.ic_len = currentOffset;
- arpIOControl.ic_dp = &arpCommandBuffer[0];
-
- // Send the ioctl.
-
- err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
- }
-
- // Clean up.
-
- if (arpStream != nil) {
- (void) OTStreamClose(arpStream);
- }
- return (err);
- }
-
- ///////////////////////////////////////////////////////////////////
-
- OSStatus ARPDeleteEntry(char *interfaceName,
- UInt32 arpProto,
- void *protoAddress, UInt32 protoSize)
- // See comment in header file.
- {
- OSStatus err;
- StreamRef arpStream;
- char arpCommandBuffer[256];
- arc_t *arpDeleteCommandPtr;
- UInt32 currentOffset;
- struct strioctl arpIOControl;
-
- // First up, open a simple stream to the ARP as a driver.
-
- arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
-
- if (err == noErr) {
- (void) OTStreamSetBlocking(arpStream);
- (void) OTStreamSetSynchronous(arpStream);
-
- // Initialise the command buffer for this command.
-
- arpDeleteCommandPtr = (arc_t *) &arpCommandBuffer[0];
- currentOffset = sizeof(arc_t);
-
- arpDeleteCommandPtr->arc_cmd = AR_ENTRY_DELETE;
-
- CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
-
- arpDeleteCommandPtr->arc_proto = arpProto;
-
- CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
-
- arpDeleteCommandPtr->arc_flags = 0; // ignored by ARP for this command
- arpDeleteCommandPtr->arc_client_q = nil; // ignored by ARP for this command
-
- // Initialise the I_STR ioctl structure.
-
- arpIOControl.ic_cmd = AR_ENTRY_DELETE;
- arpIOControl.ic_timout = 0;
- arpIOControl.ic_len = currentOffset;
- arpIOControl.ic_dp = &arpCommandBuffer[0];
-
- // Send the ioctl.
-
- err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
- }
-
- // Clean up.
-
- if (arpStream != nil) {
- (void) OTStreamClose(arpStream);
- }
- return (err);
- }
-
- ///////////////////////////////////////////////////////////////////
-
- OSStatus ARPCacheQuery(char *interfaceName,
- UInt32 arpProto,
- void *protoAddress, UInt32 protoSize,
- void *hardwareAddress, UInt32 hardwareSize, UInt32 *flags)
- // See comment in header file.
- {
- OSStatus err;
- StreamRef arpStream;
- char arpCommandBuffer[256];
- area_t *arpQueryCommandPtr;
- UInt32 currentOffset;
- struct strioctl arpIOControl;
-
- // First up, open a simple stream to the ARP as a driver.
-
- arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
-
- if (err == noErr) {
- (void) OTStreamSetBlocking(arpStream);
- (void) OTStreamSetSynchronous(arpStream);
-
- // Initialise the command buffer for this command.
-
- arpQueryCommandPtr = (area_t *) &arpCommandBuffer[0];
- currentOffset = sizeof(area_t);
-
- arpQueryCommandPtr->area_arc.arc_cmd = AR_ENTRY_SQUERY;
-
- CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
-
- arpQueryCommandPtr->area_arc.arc_proto = arpProto;
-
- CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
-
- arpQueryCommandPtr->area_arc.arc_flags = 0; // return value
- arpQueryCommandPtr->area_arc.arc_client_q = nil; // ignored by ARP for this command
-
- arpQueryCommandPtr->area_proto_mask_offset = 0; // ignored by ARP for this command
-
- arpQueryCommandPtr->area_hw_addr_offset = currentOffset;
- arpQueryCommandPtr->area_hw_addr_length = hardwareSize;
- currentOffset += hardwareSize; // space for return value
-
- // Initialise the I_STR ioctl structure.
-
- arpIOControl.ic_cmd = AR_ENTRY_SQUERY;
- arpIOControl.ic_timout = 0;
- arpIOControl.ic_len = currentOffset;
- arpIOControl.ic_dp = &arpCommandBuffer[0];
-
- // Send the ioctl.
-
- err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
- }
- if (err == noErr) {
-
- // Copy results out to client buffer.
-
- OTMemcpy( hardwareAddress, // dest
- &arpCommandBuffer[arpQueryCommandPtr->area_hw_addr_offset], // source
- hardwareSize); // length
- *flags = arpQueryCommandPtr->area_arc.arc_flags;
- }
-
- // Clean up.
-
- if (arpStream != nil) {
- (void) OTStreamClose(arpStream);
- }
- return (err);
- }
-
- ///////////////////////////////////////////////////////////////////
-
- // The ARPInterfaceInfo structure is used to record all the information this
- // module stores about an interface that it brings up. When
- // you call ARPInterfaceUp, the interfaceCookie result is really
- // a pointer to one of these structures.
-
- struct ARPInterfaceInfo {
- StreamRef interfaceStream; // The ARP stream for the interface.
- char interfaceName[256]; // The interface name, as calculated by GetARPInterfaceName.
- };
- typedef struct ARPInterfaceInfo ARPInterfaceInfo, *ARPInterfaceInfoPtr;
-
- static OSStatus GetARPInterfaceName(ARPInterfaceInfoPtr interfaceInfo)
- // Get the name for an interface on which we're about to bring up
- // ARP. ARP forms the interface name by taking the name of the module
- // and appending a number, starting at 0, to make it unique. Unfortunately
- // we have no way of determining which interfaces are already in use
- // by ARP, so we can't tell what number it will assign. Therefore
- // this sample just takes a guess, assuming 0.
- // The routine gets the name of the module using the I_LIST ioctl,
- // which returns a list of the module names on a stream, and looking
- // for the last module name in the stream, ie the driver. There
- // really shouldn't be more than one module in the stream, so the
- // array of 10 str_mlist we allocate for the return result should be
- // more than enough.
- {
- OSStatus err;
- struct str_list streamList;
- struct str_mlist streamListNames[10];
-
- streamList.sl_nmods = 10;
- streamList.sl_modlist = streamListNames;
- err = OTStreamIoctl(interfaceInfo->interfaceStream, I_LIST, &streamList);
- if (err >= noErr) {
- if ( streamList.sl_nmods == 0 ) {
- err = -5;
- } else {
- OTStrCopy(interfaceInfo->interfaceName, streamListNames[ streamList.sl_nmods-1 ].l_name );
- OTStrCat(interfaceInfo->interfaceName, "0");
- }
- }
-
- return (err);
- }
-
- static OSStatus SendARPInterfaceUpDown(ARPInterfaceInfoPtr interfaceInfo, UInt32 arpCommand)
- // Send an AR_INTERFACE_UP or AR_INTERFACE_DOWN command to the
- // ARP interface we just created. The name of the interface
- // and the controlling stream for the interface are contained
- // in the interfaceInfo pointer. arpCommand is the actual
- // command to send, ie either AR_INTERFACE_UP or AR_INTERFACE_DOWN.
- {
- OSStatus err;
- char arpCommandBuffer[256];
- arc_t *arpCommandPtr;
- UInt32 currentOffset;
- struct strioctl arpIOControl;
-
- // Initialise the command buffer for this command.
-
- arpCommandPtr = (arc_t *) &arpCommandBuffer[0];
- currentOffset = sizeof(arc_t);
-
- arpCommandPtr->arc_cmd = arpCommand;
-
- CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceInfo->interfaceName);
-
- arpCommandPtr->arc_proto = 0; // ignored by ARP for this command
-
- arpCommandPtr->arc_proto_addr_offset = 0; // ignored by ARP for this command
- arpCommandPtr->arc_proto_addr_length = 0; // ignored by ARP for this command
-
- arpCommandPtr->arc_flags = 0; // ignored by ARP for this command
- arpCommandPtr->arc_client_q = nil; // ignored by ARP for this command
-
- // Initialise the I_STR ioctl structure.
-
- arpIOControl.ic_cmd = arpCommand;
- arpIOControl.ic_timout = 0;
- arpIOControl.ic_len = currentOffset;
- arpIOControl.ic_dp = &arpCommandBuffer[0];
-
- // Send the ioctl.
-
- err = OTStreamIoctl(interfaceInfo->interfaceStream, I_STR, &arpIOControl);
-
- return (err);
- }
-
- OSStatus ARPInterfaceUp(char *configString, UInt32 *interfaceCookie)
- // See comment in header file.
- {
- OSStatus err;
- ARPInterfaceInfoPtr interfaceInfo;
- OTConfiguration *arpConfig;
-
- // Prepare for failure.
-
- arpConfig = nil;
-
- // Create a record which we use to hold all the information
- // about this interface. The address of this record is passed
- // back to the client as the interfaceCookie.
-
- err = noErr;
- interfaceInfo = (ARPInterfaceInfoPtr) OTAllocMem(sizeof(ARPInterfaceInfo));
- if ( interfaceInfo == nil) {
- err = kENOMEMErr;
- } else {
- OTMemzero(interfaceInfo, sizeof(ARPInterfaceInfo));
- }
-
- // Now create a configuration from the supplied configString...
-
- if (err == noErr) {
- arpConfig = OTCreateConfiguration(configString);
- if (arpConfig == kOTNoMemoryConfigurationPtr) {
- err = kENOMEMErr;
- } else if (arpConfig == kOTInvalidConfigurationPtr) {
- err = kENXIOErr;
- }
- }
-
- // ... and push the ARP module on top of this configuration.
- // Don't ask me why you have to do this or I'll start to
- // whimper.
-
- if (err == noErr) {
- (void) OTCfigPushParent(arpConfig, MI_ARPM_NAME, &err);
- }
-
- // Now create a stream to device driver over which we'll
- // be running ARP. Note the use OTCreateStream rather than
- // OTStreamOpen. This is because the device driver might
- // have extra plumbing underneath it (eg an ATM LANE emulation
- // driver running over an ATM hardware driver), and just
- // opening the driver would not give the driver's configurator
- // chance to set up this plumbing.
-
- if (err == noErr) {
- interfaceInfo->interfaceStream = OTCreateStream(arpConfig, 0, &err);
- if (err != noErr) {
- // Most OT create/open routines seem to return nil if they fail
- // with an error, however it seems that OTCreateSteam is not
- // as friendly. So if we get an error we nil out our record
- // of the stream to avoid trying to OTStreamClose a bogus stream
- // as we clean up.
- interfaceInfo->interfaceStream = nil;
- }
- arpConfig = nil;
- }
-
- // Get the name of the interface that ARP will create when
- // we start running it over our newly created stream.
-
- if (err == noErr) {
- (void) OTStreamSetBlocking(interfaceInfo->interfaceStream);
- (void) OTStreamSetSynchronous(interfaceInfo->interfaceStream);
- err = GetARPInterfaceName(interfaceInfo);
- }
-
- // Push ARP on top of the driver stream and then tell it that
- // the corresponding interface is up. ARP will then consider
- // the interface to be active. It will snarf ARP responses
- // as they go across the network, and you can use the
- // cache query, add and remove commands on that interface.
-
- if (err == noErr) {
- err = OTStreamIoctl(interfaceInfo->interfaceStream, I_PUSH, MI_ARPM_NAME);
- }
- if (err == noErr) {
- err = SendARPInterfaceUpDown(interfaceInfo, AR_INTERFACE_UP);
- }
-
- // Clean up after failure.
-
- if (err != noErr) {
- if (interfaceInfo != nil) {
- if ( interfaceInfo->interfaceStream != nil ) {
- OTStreamClose( interfaceInfo->interfaceStream );
- }
- OTFreeMem(interfaceInfo);
- interfaceInfo = nil;
- }
- }
-
- // General clean up.
-
- if (arpConfig != nil) {
- OTDestroyConfiguration(arpConfig);
- }
-
- // Regardless of error result, copy interfaceInfo out to client buffer.
- // This ensures that the client gets a nil cookie when we get an error.
-
- *interfaceCookie = (UInt32) interfaceInfo;
-
- return (err);
- }
-
- ///////////////////////////////////////////////////////////////////
-
- OSStatus ARPInterfaceDown(UInt32 interfaceCookie)
- // See comment in header file.
- {
- OSStatus err;
- ARPInterfaceInfoPtr interfaceInfo;
-
- interfaceInfo = (ARPInterfaceInfoPtr) interfaceCookie;
-
- // First tell ARP we're about to bring the interface down.
-
- err = SendARPInterfaceUpDown(interfaceInfo, AR_INTERFACE_DOWN);
-
- // Now close the stream that we opened to run the interface
- // over.
- if (err == noErr) {
- (void) OTStreamClose( interfaceInfo->interfaceStream );
- OTFreeMem(interfaceInfo);
- }
-
- return (err);
- }
-